home *** CD-ROM | disk | FTP | other *** search
/ Mac Easy 2010 May / Mac Life Ubuntu.iso / casper / filesystem.squashfs / usr / share / pyshared / Onboard / OnboardCommon.py < prev    next >
Encoding:
Python Source  |  2008-03-03  |  20.7 KB  |  528 lines

  1. # -*- coding: UTF-8 -*-
  2.  
  3. from xml.dom import minidom
  4. import sys
  5. import gobject
  6. gobject.threads_init()
  7.  
  8. import gtk
  9. import re
  10. import string
  11. import virtkey
  12. import gconf
  13. import gettext
  14. import os.path
  15. import gettext
  16. from gettext import gettext as _
  17.  
  18. from Onboard.Keyboard import Keyboard
  19. from Onboard.Key import * 
  20. from Onboard.Pane import Pane
  21. from Onboard.KbdWindow import KbdWindow
  22.  
  23. import Onboard.utils as utils
  24.  
  25. #setup gettext
  26. app="onboard"
  27. gettext.textdomain(app)
  28. gettext.bindtextdomain(app)
  29.  
  30. DEFAULT_FONTSIZE = 25
  31.  
  32. class OnboardGtk(object):
  33.     """
  34.     This class is a mishmash of things that I didn't have time to refactor in to seperate classes.
  35.     It needs a lot of work.
  36.     The name comes from onboards original working name of simple onscreen keyboard.  
  37.     """
  38.     def __init__(self):
  39.         # This is done so multiple keys with the same modifier don't interfere with each other.
  40.         self.mods = {1:0,2:0, 4:0,8:0, 16:0,32:0,64:0,128:0}
  41.  
  42.         # this is used in various places it is the directory containing this file.          
  43.         self.SOK_INSTALL_DIR = '/usr/share/onboard'
  44.         sys.path.append(os.path.join(self.SOK_INSTALL_DIR,'scripts'))
  45.         
  46.         # this object is the source of all layout info and where we send key presses to be emulated.
  47.         self.vk = virtkey.virtkey()
  48.  
  49.         self.gconfClient = gconf.client_get_default()
  50.         # Get the location of the current layout .sok file from gconf.
  51.         self.gconfClient.add_dir("/apps/sok",gconf.CLIENT_PRELOAD_NONE)
  52.         filename = self.gconfClient.get_string("/apps/sok/layout_filename")
  53.         if not filename or not os.path.exists(filename):
  54.             self.load_default_layout()
  55.         else:
  56.             self.load_layout(filename)
  57.         
  58.         # populates list of macros or "snippets" from gconf
  59.         self.macros = self.gconfClient.get_list("/apps/sok/macros",gconf.VALUE_STRING)
  60.         
  61.         self.window = KbdWindow(self)
  62.         self.window.set_keyboard(self.keyboard)
  63.  
  64.         
  65.         #Create menu for trayicon
  66.         uiManager = gtk.UIManager()
  67.         
  68.         actionGroup = gtk.ActionGroup('UIManagerExample')
  69.         actionGroup.add_actions([('Quit', gtk.STOCK_QUIT, _('_Quit'), None,
  70.                                   _('Quit onBoard'), self.quit),
  71.                                  ('Settings', gtk.STOCK_PREFERENCES, _('_Settings'), None, _('Show settings'), self.cb_settings_item_clicked)])
  72.  
  73.         uiManager.insert_action_group(actionGroup, 0)
  74.  
  75.         uiManager.add_ui_from_string("""<ui>
  76.                         <popup>
  77.                             <menuitem action="Settings"/>
  78.                             <menuitem action="Quit"/>
  79.                         </popup>
  80.                     </ui>""")
  81.         trayMenu = uiManager.get_widget("/ui/popup")
  82.  
  83.         # Create the trayicon 
  84.         try:
  85.             self.statusIcon = gtk.status_icon_new_from_file("%s/onboard.svg" % self.SOK_INSTALL_DIR)
  86.             self.statusIcon.connect("activate", self.cb_status_icon_clicked)
  87.             self.statusIcon.connect("popup-menu", self.cb_status_icon_menu, trayMenu)
  88.  
  89.  
  90.             if not self.gconfClient.get_bool("/apps/sok/trayicon"):
  91.                 self.hide_status_icon()
  92.             else:
  93.                 self.show_status_icon()
  94.             
  95.         except AttributeError:
  96.             print _("You need pygtk 2.10 or above for the system tray icon")
  97.         
  98.  
  99.         self.window.hidden = False
  100.  
  101.         self.window.show_all()
  102.         
  103.         # Watch settings for changes
  104.         self.gconfClient.notify_add("/apps/sok/sizeX",self.window.do_set_size)
  105.         self.gconfClient.notify_add("/apps/sok/layout_filename",self.do_set_layout)
  106.         self.gconfClient.notify_add("/apps/sok/macros",self.do_change_macros)
  107.         self.gconfClient.notify_add("/apps/sok/scanning_interval", self.do_change_scanningInterval)
  108.         self.gconfClient.notify_add("/apps/sok/scanning", self.do_change_scanning)
  109.         self.gconfClient.notify_add("/apps/sok/trayicon", self.do_set_trayicon)
  110.                 
  111.         
  112.         scanning = self.gconfClient.get_bool("/apps/sok/scanning")
  113.         if scanning:
  114.             self.scanning = scanning
  115.             self.keyboard.reset_scan()
  116.         else:
  117.             self.scanning = False
  118.         
  119.         scanningInterval = self.gconfClient.get_int("/apps/sok/scanning_interval")
  120.         if scanningInterval:
  121.             self.scanningInterval = scanningInterval
  122.         else:
  123.             self.gconfClient.set_int("/apps/sok/scanning_interval",750)
  124.         
  125.         # code moved from 'onboard' executable
  126.         gtk.main()
  127.         self.clean()
  128.     
  129.     def cb_settings_item_clicked(self,widget):
  130.         """
  131.         Callback called when setting button clicked in the trayicon menu. 
  132.         """
  133.         utils.run_script("sokSettings",self)
  134.  
  135.     def cb_status_icon_menu(self,status_icon, button, activate_time,trayMenu):
  136.         """
  137.         Callback called when trayicon right clicked.  Produces menu.
  138.         """
  139.         trayMenu.popup(None, None, gtk.status_icon_position_menu, 
  140.              button, activate_time, status_icon)    
  141.  
  142.     def do_set_trayicon(self, cxion_id=None, entry=None, user_data=None,thing=None):
  143.         """
  144.         Callback called when gconf detects that the gconf key specifying 
  145.         whether the trayicon should be shown or not is changed.
  146.         """
  147.         if self.gconfClient.get_bool("/apps/sok/trayicon"):
  148.             self.show_status_icon()
  149.         else:
  150.             self.hide_status_icon()
  151.         
  152.     def show_status_icon(self):     
  153.         """
  154.         Shows the status icon.  When it is shown we set a wm hint so that
  155.         onboard does not appear in the taskbar.
  156.         """
  157.         self.statusIcon.set_visible(True)
  158.         self.window.set_property('skip-taskbar-hint', True)
  159.  
  160.     def hide_status_icon(self):
  161.         """
  162.         The opposite of the above.
  163.         """
  164.         self.statusIcon.set_visible(False)
  165.         self.window.set_property('skip-taskbar-hint', False)
  166.  
  167.     def cb_status_icon_clicked(self,widget):
  168.         """
  169.         Callback called when trayicon clicked.
  170.         Toggles whether onboard window visibile or not.
  171.  
  172.         TODO would be nice if appeared to iconify to taskbar
  173.         """
  174.         if self.window.hidden:
  175.             self.window.deiconify()
  176.             self.window.hidden = False          
  177.         else:
  178.             self.window.iconify()
  179.             self.window.hidden = True
  180.             
  181.             
  182.         
  183.  
  184.     def unstick(self):
  185.         for key in self.keyboard.basePane.keys.values():
  186.             if key.on :
  187.                 self.keyboard.release_key(key)
  188.             
  189.         
  190.     def clean(self): #Called when sok is gotten rid off.
  191.         self.unstick()
  192.         self.window.hide()
  193.         
  194.     def quit(self, widget=None):
  195.         self.clean()
  196.         gtk.main_quit()
  197.             
  198.     def do_change_scanning(self, cxion_id, entry, user_data,thing):
  199.         self.scanning = self.gconfClient.get_bool("/apps/sok/scanning")
  200.         self.keyboard.reset_scan()
  201.     
  202.     def do_change_scanningInterval(self, cxion_id, entry, user_data,thing):
  203.         self.scanningInterval = self.gconfClient.get_int("/apps/sok/scanningInterval")
  204.     
  205.     def do_change_macros(self,client, cxion_id,entry,user_data):
  206.         self.macros = self.gconfClient.get_list("/apps/sok/macros",gconf.VALUE_STRING)
  207.           
  208.  
  209.     def do_set_layout(self,client, cxion_id, entry, user_data):
  210.         self.unstick()
  211.         filename = self.gconfClient.get_string("/apps/sok/layout_filename")
  212.         if os.path.exists(filename):
  213.             self.load_layout(filename)
  214.             self.window.set_keyboard(self.keyboard)
  215.         else:
  216.             self.load_default_layout()
  217.  
  218.         self.window.set_keyboard(self.keyboard)
  219.     
  220.     def hexstring_to_float(self,hexString): 
  221.         return float(string.atoi(hexString,16))
  222.  
  223.     
  224.     def get_sections_keys(self,section,keys,pane,xOffset,yOffset):
  225.         "gets keys for a specified sections from the XServer."
  226.         rows = self.vk.layout_get_keys(section)
  227.         
  228.         for row in rows:
  229.             for key in row:
  230.                 shape = key['shape']
  231.                 name = key['name'].strip(chr(0)) #since odd characters after names shorter than 4.
  232.                 
  233.                 if name in utils.modDic:
  234.                     nkey = RectKey(pane,float(shape[0] + xOffset),float(shape[1] + yOffset), float(shape[2]), float(shape[3]),(0.95,0.9,0.85,1))
  235.                     props = utils.modDic[name]
  236.                     
  237.                     actions = ("","","",props[1],"")
  238.                     labels =(props[0],"","","","")
  239.                     sticky = True
  240.                 
  241.                 else:            
  242.                     actions = ("",key['keysym'],"","","","")
  243.                     
  244.                     if name in utils.otherDic:
  245.                         
  246.                         nkey = RectKey(pane,float(shape[0] + xOffset),float(shape[1] + yOffset), float(shape[2]), float(shape[3]),(0.85,0.8,0.65,1))
  247.                         labels= (utils.otherDic[name],"","","","")
  248.                     else:
  249.                         nkey = RectKey(pane,float(shape[0]+ xOffset),float(shape[1] + yOffset), float(shape[2]), float(shape[3]),(0.9,0.85,0.7,1))
  250.                         labDic = key['labels']
  251.                         labels = (labDic[0],labDic[2],labDic[1],labDic[3],labDic[4])
  252.                         
  253.                     sticky = False
  254.                     
  255.                     
  256.                 nkey.set_properties(actions, labels, sticky,0,0)
  257.                     
  258.                 keys[name] =  nkey
  259.     
  260.     def load_default_layout(self):
  261.         panes = []
  262.         
  263.         sizeA = self.vk.layout_get_section_size("Alpha")
  264.         sizeK = self.vk.layout_get_section_size("Keypad") 
  265.         sizeE = self.vk.layout_get_section_size("Editing")
  266.         sizeF = (294, 94)
  267.         #Tidy this up
  268.         
  269.         
  270.         listX = [sizeA[0],sizeE[0] + sizeK[0] + 20 + 125 ,sizeF[0]]
  271.         listY = [sizeA[1]+ 1,sizeE[1] + 3, sizeK[1]+3,64 ,sizeF[1]] #alpha,editing,keypad,macros,functions
  272.         listX.sort()
  273.         listY.sort()
  274.         sizeX = listX[len(listX)-1]
  275.         sizeY = listY[len(listY)-1]
  276.             
  277.     
  278.     
  279.         keys = {}
  280.         pane = Pane(self,"Alpha", keys,None, float(sizeX), float(sizeY), [0,0,0,0.3],DEFAULT_FONTSIZE)
  281.         panes.append(pane)
  282.         self.get_sections_keys("Alpha", keys,pane,0,0)
  283.             
  284.                 
  285.         keys = {}
  286.         pane = Pane(self,"Editing",keys,None, float(sizeX), float(sizeY), [0.3,0.3,0.7,0.3],DEFAULT_FONTSIZE)
  287.         panes.append(pane)  
  288.         self.get_sections_keys("Editing", keys, pane, 0, 2)
  289.         self.get_sections_keys("Keypad", keys, pane, sizeE[0] + 20 , 2)
  290.         
  291.         for r in range(3):
  292.             for c in range(3):
  293.                 n = c + r*3
  294.                 mkey = RectKey(pane,sizeE[0] +sizeK[0] +45 + c*30, 7 + r*28, 25, 24,(0.5,0.5,0.8,1))
  295.                 mkey.set_properties(("", "", "", "",("%d" %n) ),(_("Snippit\n%d") % (n),"","","",""), False,0,0)
  296.                 keys["m%d" % (n)] = mkey
  297.         
  298.         keys = {}
  299.         pane = Pane(self,"Functions",keys,None, float(sizeX), float(sizeY), [0.6,0.3,0.7,0.3], DEFAULT_FONTSIZE)
  300.         panes.append(pane)
  301.         y = 0
  302.         for n in range(len(utils.funcKeys)):
  303.             if n  >=8:
  304.                 y = 27
  305.                 m = n -8
  306.             else :
  307.                 m = n
  308.             
  309.             fkey = RectKey(pane,5 + m*30, 5 + y, 25, 24,(0.5,0.5,0.8,1))
  310.             fkey.set_properties(("", utils.funcKeys[n][1], "", ""),(utils.funcKeys[n][0],"","","",""), False,0,0)
  311.             keys[utils.funcKeys[n][0]] = fkey
  312.         
  313.         settingsKey = RectKey(pane,5, 61, 60.0, 30.0,(0.95,0.5,0.5,1))
  314.         settingsKey.set_properties(("","","","","","sokSettings"), (_("Settings"),"","","",""), False,0,0)
  315.         keys["settings"] = settingsKey
  316.         
  317.         switchingKey = RectKey(pane,70 ,61,60.0,30.0,(0.95,0.5,0.5,1))
  318.         switchingKey.set_properties(("","","","","","switchButtons"), (_("Switch\nButtons"),"","","",""), False,0,0)
  319.         keys["switchButtons"] = switchingKey
  320.         
  321.         
  322.         basePane = panes[0]
  323.         otherPanes = panes[1:]
  324.  
  325.         self.keyboard = Keyboard(self,basePane,otherPanes)
  326.         for pane in panes:
  327.             pane.set_DrawingArea(self.keyboard)     
  328.                 
  329.     
  330.     
  331.     def load_keys(self,doc,keys):
  332.         
  333.             for key in doc.getElementsByTagName("key"):  
  334.                 try:
  335.                     if key.attributes["id"].value in keys:
  336.                         actions = ["","","","","",""]
  337.                         if key.hasAttribute("char"):
  338.                             actions[0] = key.attributes["char"].value
  339.                         elif key.hasAttribute("keysym"):
  340.                             value = key.attributes["keysym"].value
  341.                             if value[1] == "x":#Deals for when keysym is a hex value.
  342.                                 actions[1] = string.atoi(value,16)
  343.                             else:
  344.                                 actions[1] = string.atoi(value,10)
  345.                         elif key.hasAttribute("press"):
  346.                             actions[2] = key.attributes["press"].value
  347.                         elif key.hasAttribute("modifier"):
  348.                             actions[3] = modifiers[key.attributes["modifier"].value]
  349.                         elif key.hasAttribute("macro"):
  350.                             actions[4] = key.attributes["macro"].value
  351.                         elif key.hasAttribute("script"):
  352.                             actions[5] = key.attributes["script"].value
  353.  
  354.                         labels = ["","","","",""]
  355.                         if key.hasAttribute("label"):
  356.                             labels[0] = key.attributes["label"].value
  357.                         if key.hasAttribute("cap_label"):
  358.                             labels[1] = key.attributes["cap_label"].value
  359.                         if key.hasAttribute("shift_label"):
  360.                             labels[2] = key.attributes["shift_label"].value
  361.                         if key.hasAttribute("altgr_label"):
  362.                             labels[3] = key.attributes["altgr_label"].value
  363.                         if key.hasAttribute("altgrNshift_label"):
  364.                             labels[4] = key.attributes["altgrNshift_label"].value   
  365.                     
  366.                         if key.hasAttribute("font_offset_x"):
  367.                             offsetX = float(key.attributes["font_offset_x"].value)
  368.                         else:
  369.                             offsetX = 0
  370.                         
  371.                         if key.hasAttribute("font_offset_y"):
  372.                             offsetY = float(key.attributes["font_offset_y"].value)
  373.                         else:
  374.                             offsetY = 0
  375.                         
  376.                         
  377.                         stickyString = key.attributes["sticky"].value
  378.                         if stickyString == "true":
  379.                             sticky = True
  380.                         else:
  381.                             sticky= False
  382.                         
  383.                         keys[key.attributes["id"].value].set_properties(actions,
  384.                                             labels,
  385.                                             sticky, offsetX, offsetY)
  386.                 except KeyError, (strerror):
  387.                     print "key missing id"
  388.  
  389.     def load_layout(self,kblang):
  390.         
  391.         kbfolder = os.path.dirname(kblang)
  392.  
  393.         f = open(kblang)
  394.         langdoc = minidom.parse(f).documentElement
  395.         f.close()
  396.             
  397.             
  398.         panes = []
  399.         
  400.         for paneXML in langdoc.getElementsByTagName("pane"):
  401.             
  402.             try:
  403.                 path= "%s/%s" % (kbfolder,paneXML.attributes["filename"].value)
  404.                 
  405.                 
  406.                 f = open(path)
  407.                 try:            
  408.                     svgdoc = minidom.parse(f).documentElement
  409.                     keys = {}
  410.  
  411.                     try:
  412.                         viewPortSizeX = float(svgdoc.attributes['width'].value)
  413.                         viewPortSizeY = float(svgdoc.attributes['height'].value)
  414.                     except ValueError:
  415.                         print "Units for canvas height and width must be px.  In the svg file this corresponds with having no units after the height and width"
  416.  
  417.                     #find background of pane
  418.                     paneBackground = [0.0,0.0,0.0,0.0]
  419.             
  420.                     if paneXML.hasAttribute("backgroundRed"):
  421.                         paneBackground[0] = paneXML.attributes["backgroundRed"].value
  422.                     if paneXML.hasAttribute("backgroundGreen"):
  423.                         paneBackground[1] = paneXML.attributes["backgroundGreen"].value
  424.                     if paneXML.hasAttribute("backgroundBlue"):
  425.                         paneBackground[2] = paneXML.attributes["backgroundBlue"].value
  426.                     if paneXML.hasAttribute("backgroundAlpha"):
  427.                         paneBackground[3] = paneXML.attributes["backgroundAlpha"].value
  428.  
  429.                     #scanning
  430.                     columns = []
  431.                     
  432.                     
  433.                     if paneXML.hasAttribute("font"):
  434.                         fontSize = string.atoi(paneXML.attributes["font"].value)
  435.                     else:
  436.                         fontSize = DEFAULT_FONTSIZE
  437.                     
  438.                     pane = Pane(self,paneXML.attributes["id"].value,keys,columns, viewPortSizeX, viewPortSizeY, paneBackground, fontSize)
  439.  
  440.                     
  441.                     for rect in svgdoc.getElementsByTagName("rect"): 
  442.                         id = rect.attributes["id"].value
  443.                         
  444.                         styleString = rect.attributes["style"].value
  445.                         result = re.search("(fill:#\d?\D?\d?\D?\d?\D?\d?\D?\d?\D?\d?\D?;)", styleString).groups()[0]
  446.                 
  447.                         rgba = [self.hexstring_to_float(result[6:8])/255,
  448.                         self.hexstring_to_float(result[8:10])/255,
  449.                         self.hexstring_to_float(result[10:12])/255,
  450.                         1]#not bothered for now 
  451.  
  452.                         keys[id] = RectKey(pane,float(rect.attributes['x'].value),
  453.                                         float(rect.attributes['y'].value),
  454.                                         float(rect.attributes['width'].value),
  455.                                         float(rect.attributes['height'].value),rgba)
  456.                     
  457.                     
  458.                     
  459.                     for path in svgdoc.getElementsByTagName("path"):
  460.                         id = path.attributes["id"].value
  461.                         styleString = rect.attributes["style"].value
  462.                         result = re.search("(fill:#\d?\D?\d?\D?\d?\D?\d?\D?\d?\D?\d?\D?;)", styleString).groups()[0]
  463.                 
  464.                         rgba = (self.hexstring_to_float(result[6:8])/255,
  465.                         self.hexstring_to_float(result[8:10])/255,
  466.                         self.hexstring_to_float(result[10:12])/255,
  467.                         1)#not bothered for now
  468.  
  469.                         dList = path.attributes["d"].value.split(" ")
  470.                         dList = dList[1:-2] #trim unwanted M, Z
  471.                         coordList = []
  472.                         for d in dList:
  473.                             l = d.split(",")
  474.                             for p in l:
  475.                                 if len(p) == 1:
  476.                                     coordList.append(p)
  477.                                 else:
  478.                                     coordList.append(float(p))
  479.  
  480.                         keys[id] = LineKey(pane,coordList,rgba)
  481.                     
  482.                                             
  483.                     
  484.                     svgdoc.unlink()
  485.                     
  486.                     self.load_keys(langdoc,keys)
  487.                     
  488.                     try:
  489.                         
  490.                         for columnXML in paneXML.getElementsByTagName("column"):
  491.                             column = []
  492.                             columns.append(column)
  493.                             for scanKey in columnXML.getElementsByTagName("scankey"):
  494.                                 column.append(keys[scanKey.attributes["id"].value])
  495.                     except KeyError, (strerror):
  496.                         print "require %s key, appears in scanning only" % (strerror)
  497.                     
  498.  
  499.                     panes.append(pane)
  500.                 except KeyError, (strerror):
  501.                     print _("require %s") % (strerror)
  502.                     
  503.                 f.close()
  504.             except KeyError:
  505.                 print _("require filename in pane")
  506.         
  507.         langdoc.unlink()
  508.         
  509.         
  510.         basePane = panes[0]
  511.         otherPanes = panes[1:]
  512.  
  513.         self.keyboard = Keyboard(self,basePane,otherPanes)
  514.         for pane in panes:
  515.             pane.set_DrawingArea(self.keyboard)
  516.  
  517.         
  518.  
  519.             
  520.  
  521.  
  522.  
  523.     
  524. if __name__=='__main__':
  525.     s = Sok()
  526.     gtk.main()
  527.     s.clean()
  528.